#!/bin/bash

#    / **  
#    * 文件名：安装linux软件
#    * 版权： Copyright 谢振斌  All Rights Reserved.  
#    * 修改内容：新增  
#    * 修改人： 谢振斌  
#    * 修改时间：2025-6-30  
#    */  

# 初始化参数
TEST_MODE=false
ALL_SOFTWARE=false
DIY_SOFTWARE=""
OUTPUT_DIR="$HOME/Downloads/Software"
# LOG_FILE="/tmp/software_install.log"
shellfilepath="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

#    / ** 
#    * 日志函数
#    */  
function xecho() {
    local flag="$1"
    local message="$2"
    local timestamp=$(date +"%T")
    local color_code=""
    
    case "$flag" in
        INFO)    color_code="\033[0;37m" ;;
        Info)    color_code="\033[0;32m" ;;
        WARNING) color_code="\033[0;33m" ;;
        DEBUG)   color_code="\033[0;34m" ;;
        Debug)   color_code="\033[0;34m" ;;
        debug)   color_code="\033[0;34m" ;;
        ERROR)   color_code="\033[0;31m" ;;
        SUCCESS) color_code="\033[0;32m" ;;
        *)       color_code="\033[0m"    ;;
    esac
    
    if [[ "$TEST_MODE" == "true" ]]; then
        echo -e "${color_code}[$flag][$timestamp] $message\033[0m"
    elif [[ "$flag" == "ERROR" || "$flag" == "INFO" || "$flag" == "Info" || "$flag" == "WARNING" ||"$flag" == "SUCCESS"  ]]; then
        echo -e "${color_code}[$flag][$timestamp] $message\033[0m"
    fi
}

# 设置参数函数
si=0
function set_software_list() {
    software_name[$si]="$1" # 软件名
    software_check[$si]="$2" # 软件检查
    software_descriptions[$si]="$3"  # 描述
    software_url[$si]="$4"  # 软件官网或下载地址
    software_down_url[$si]="$5" # 软件指定下载地址
    # software_install_commands[$si]="$6"  # 软件安装命令或安装函数
    # xecho "DEBUG" "\$6 = $6"
    local install_cmd=""
    for ((arg_index=6; arg_index<=$#; arg_index++)); do
        install_cmd+="${!arg_index} "  # 间接引用获取参数
    done
    # xecho "DEBUG" "install_cmd = $install_cmd"
    software_install_commands[$si]="${install_cmd% }"  # 移除末尾空格
    si=$(($si+1))
}

unsi=0
function set_uninstall_software_list() {
    uninstall_software_name[$unsi]="$1" # 软件名
    uninstall_software_check[$unsi]="$2" # 软件检查
    uninstall_software_descriptions[$unsi]="$3"  # 描述
    uninstall_software_url[$unsi]="$4"  # 软件官网或下载地址
    uninstall_software_down_url[$unsi]="$5" # 软件指定下载地址
    # uninstall_software_install_commands[$unsi]="$6"  # 软件安装命令或安装函数
    # xecho "DEBUG" "\$6 = $6"
    local install_cmd=""
    for ((arg_index=6; arg_index<=$#; arg_index++)); do
        install_cmd+="${!arg_index} "  # 间接引用获取参数
    done
    # xecho "DEBUG" "install_cmd = $install_cmd"
    uninstall_software_install_commands[$unsi]="${install_cmd% }"  # 移除末尾空格
    unsi=$(($unsi+1))
}

edsi=0
function set_installed_software_list() {
    installed_software_name[$edsi]="$1" # 软件名
    installed_software_check[$edsi]="$1" # 软件名
    installed_software_descriptions[$edsi]="$2"  # 描述
    installed_software_url[$edsi]="$3"  # 软件官网或下载地址
    installed_software_down_url[$edsi]="$4" # 软件指定下载地址
    # installed_software_install_commands[$edsi]="$5"  # 软件安装命令或安装函数
    # xecho "DEBUG" "\$6 = $6"
    local install_cmd=""
    for ((arg_index=6; arg_index<=$#; arg_index++)); do
        install_cmd+="${!arg_index} "  # 间接引用获取参数
    done
    # xecho "DEBUG" "\install_cmd = $install_cmd"
    installed_software_install_commands[$edsi]="${install_cmd% }"  # 移除末尾空格
    edsi=$(($edsi+1))
}

# 加载软件列表配置文件
CONFIG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# source "${CONFIG_DIR}/software_list.sh"
# source "${CONFIG_DIR}/software_list1.sh"
# source "${CONFIG_DIR}/software_list_tui.sh"

# 根据不同类型系统选择不同的软件列表
shellostypestring=`echo $OSTYPE`;
## echo "[Debug] shellostypestring=${shellostypestring}"
xecho "INFO" "操作系统类型：$shellostypestring"  
## 从字符串中识别shell系统类型
case "${shellostypestring}" in
    *'linux'*   ) 
        # SHELL_PLATFORM='linux'
        source "${CONFIG_DIR}/software_list_linux.sh"  
        ;;
    *'darwin'*  ) SHELL_PLATFORM='osx'
        source "${CONFIG_DIR}/software_list_osx.sh"     
        ;;
    *'bsd'*     ) 
        # SHELL_PLATFORM='bsd'
        source "${CONFIG_DIR}/software_list_bsd.sh"
        ;;
    *)
        xecho "INFO" "未知系统：$shellostypestring" 
        source "${CONFIG_DIR}/software_list_example.sh"
        ;;
esac

# 内容例子：
# 软件列表
#                   软件名  检查         描述        官网                                 指定要软件包下载        安装命令
# set_software_list  "git"   "git"     "版本控制器"    "https://git-scm.com/downloads"   "指定要软件包下载"    "brew install git"
# set_software_list  "helix"  "hx"    "后现代编辑器"   "https://helix-editor.cn/"   "指定要软件包下载"   "install_software_fun1"


# 加载安装函数定义脚本文件
source "${CONFIG_DIR}/install_fun.sh"


# 安全执行安装命令
function xeval(){
    local cmd="$1"
    xecho "DEBUG" "执行命令：$cmd"
    eval "$cmd"
    if declare -f "${cmd%% *}" > /dev/null; then 
    # 这条命令检查 ${cmd%% *}（即命令字符串的第一个单词）是否是一个已定义的函数：
        $cmd
    else
        eval "$cmd"
    fi
}


#    / **  
#    * 检查软件是否安装  
#    */ 
function check_installed() {
    local name="$1"
    if command -v "$name" &> /dev/null; then
        return 0
    elif [ -e "$name" ]; then # 检查是否为存在的文件路径
        return 0
    else
        return 1
    fi
}


#    / **  
#    * 主函数  
#    */  
function main() 
{
    # 主安装逻辑
    xecho "INFO" "开始软件安装流程"
    # ni=0
    # nj=0
    xecho "INFO" "软件列表（${#software_name[@]}）:"
    for ((i = 0; i < ${#software_name[@]}; ++i)); do
        # xecho "DBUG" "软件列表: ${i}、${software_name[$i]} - ${software_descriptions[$i]}"
        # xecho "DBUG" “$( which ${software_name[$i]})”
        # if [[ -x "$( which ${software_name[$i]})" ]]; then
        if ! check_installed ${software_check[$i]}; then
            xecho "INFO" "$(($i+1))、未安装: ${software_name[$i]} - ${software_descriptions[$i]} - ${software_url[$i]}"
            set_uninstall_software_list ${software_name[$i]} ${software_check[$i]}  ${software_descriptions[$i]} ${software_url[$i]} ${software_down_url[$i]} ${software_install_commands[$i]}
            # ni=$(($ni+1))
            # xecho "INFO" "安装: ${ni}、${software_name[$i]} - ${software_descriptions[$i]}"
        else
            # installed_software_name[$nj]=${software_name[$i]}
            set_installed_software_list ${installed_software_name[$i]} ${installed_software_check[$i]} ${installed_software_descriptions[$i]} ${installed_ssoftware_url[$i]} ${installed_software_down_url[$i]} ${installed_software_install_commands[$i]} 
            # nj=$(($nj+1))
            # xecho "INFO" "${nj}、${software_name[$i]} - ${software_descriptions[$i]} 已安装"
            xecho "Info" "$(($i+1))、已安装: ${software_name[$i]} - ${software_descriptions[$i]} - ${software_url[$i]}"
        fi
    done

    # 安装所有软件(安装未安装的软件，跳过已安装)
    if [[ "$ALL_SOFTWARE" == "true" ]]; then
        xecho "INFO" "安装所有软件(安装未安装的软件，跳过已安装)。未安装软件列表如下：（${#uninstall_software_name[@]}个）"
        for ((i = 0; i < ${#uninstall_software_name[@]}; i++)); do
            xecho "INFO" "$(($i+1))、未安装: ${uninstall_software_name[$i]} - ${uninstall_software_descriptions[$i]}"
            # xecho "INFO" "正在执行安装函数或命令：${software_install_commands[$software_id]} "
            xeval "${software_install_commands[$software_id]}"
        done
    fi
    
    # 安装指定软件
    if [[ -n "$DIY_SOFTWARE" ]]; then
        IFS=',' read -ra softwares <<< "$DIY_SOFTWARE"
        for software in "${softwares[@]}"; do
            software=$(echo "$software" | xargs)  # 去除空格
            # 先判读软件数据列表中有该软件名没，有在判读是否已安装，未安装再安装
            count=0
            for ((software_id = 0; count < ${#software_name[@]}; software_id++)); do
                if [[ "$software" == ${software_name[$software_id]} ]]; then  # 找到
                    if ! check_installed ${software_check[$software_id]} ; then
                        # xecho "INFO" "未安装 $software，现在执行安装命令：${software_install_commands[$software_id]} "
                        xeval "${software_install_commands[$software_id]}"
                        break; # 找到，执行完则立即退出循环
                    else
                        xecho "INFO" "已安装: $software - ${software_descriptions[$software_id]}"
                        break; # 找到则立即退出循环
                    fi
                fi
                count=$(($count+1))
                # xecho "Debug" "count = $count"
            done
            xecho "Debug" "count == $count"
            if [ $count -ge ${#software_name[@]} ]; then  # 遍历一遍没找到
                xecho "ERROR" "未知软件: $software"
            fi
        done
        exit 0
    fi
    
    # 交互式安装
    xecho "INFO" "选择要安装的软件:（${#uninstall_software_name[@]}）个"
    # local count=1
    local options=()
    for ((software_id = 0; software_id < ${#uninstall_software_name[@]}; software_id++)); do
        # printf "%-3s %-20s %s\n" "$(($software_id+1))." "${uninstall_software_name[$software_id]}" "${uninstall_software_descriptions[$software_id]}" 
        echo "$(($software_id+1)). ${uninstall_software_name[$software_id]} ${uninstall_software_descriptions[$software_id]} - ${uninstall_software_url[$software_id]}"
        # options[$count]="$software_id"
        # count=$((count + 1))
        # xecho "INFO" "${i}、未安装: ${uninstall_software_name[$i]} - ${uninstall_software_descriptions[$i]}"
    done

    if [[ $count -eq 1 ]]; then
        xecho "INFO" "所有软件均已安装!"
        exit 0
    fi
    
    read -p "输入选择 (多个用逗号分隔, A=全部, Q=退出): " choice
    
    case "$choice" in
        [aA]) # 安装所有未安装的软件
            for ((i = 0; i < ${#uninstall_software_name[@]}; i++)); do
                xecho "INFO" "$(($i+1))、未安装: ${uninstall_software_name[$i]} - ${uninstall_software_descriptions[$i]}"
                # 执行安装命令
                # xecho "INFO" "执行安装命令或函数：${uninstall_software_install_commands[$i]}"
                xeval "${uninstall_software_install_commands[$i]}"
            done
            ;;
        [qQ])
            xecho "INFO" "退出安装"
            exit 0
            ;;
        *)
            xecho "INFO" "选择：$choice"
            IFS=',' read -ra selections <<< "$choice"
            # for ((i = 0; i < ${#selections[@]}; i++)); do
            for selection_id in "${selections[@]}"; do
                xecho "DEBUG" "selection_id = ${selection_id}"
                # xecho "INFO" software="${options[$selection]}"
                # software="${options[$selection]}"
                real_selection_id=$(($selection_id-1))
                if [[ -n "${uninstall_software_install_commands[$real_selection_id]}" ]]; then
                    xecho "INFO" "开始安装${uninstall_software_name[$real_selection_id]}，执行安装命令或函数：${uninstall_software_install_commands[$real_selection_id]}"
                    xeval "${uninstall_software_install_commands[$real_selection_id]}"
                else
                    xecho "WARNING" "无效选择: ${selection_id}"
                fi
            done
            # for selection in "${selections[@]}"; do
            #     software="${options[$selection]}"
            #     if [[ -n "$software" ]]; then
            #         eval "${software_install_commands[$software]}"
            #     else
            #         xecho "WARNING" "无效选择: $selection"
            #     fi
            # done
            ;;
    esac
}

#    / **  
#    *〈流程控制〉  
#    *〈该脚本的主函数〉  
#    * @param [无]  
#    * @return [无]  
#    * @exception/throws [无]  
#    * @deprecated  
#    */  
function processControlMain()  
{  
    # 打印当前系统时间  
    echo "Start..."  
    echo "\$1 =$1"  
    echo "\$2 =$2"  
    date  

    # 此处是你的代码  
    # ...  
    # fun1
    echo '''
    使用说明：
    # 交互式安装
    ./install_main.sh
    # 安装所有软件
    ./install_main.sh --all
    # 安装指定软件
    ./install_main.sh --software git,vim
    # 测试模式（详细日志）
    ./install_main.sh --test --software git
    '''
    # echo ${des_string}

    # 解析命令行参数
    # while [[ $# -gt 0 ]]; do
    #     case "$1" in
    #         -t|--test)
    #             TEST_MODE=true
    #             shift
    #             ;;
    #         -a|--all)
    #             ALL_SOFTWARE=true
    #             shift
    #             ;;
    #         -s|--software)
    #             DIY_SOFTWARE="$2"
    #             shift 2
    #             ;;
    #         -o|--output)
    #             OUTPUT_DIR="$2"
    #             shift 2
    #             ;;
    #         *)
    #             xecho "ERROR" "未知参数: $1"
    #             exit 1
    #             ;;
    #     esac
    # done
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -t|--test)
                TEST_MODE=true
                shift
                ;;
            -a|--all)
                ALL_SOFTWARE=true
                shift
                ;;
            -s|--software)
                # 检查是否提供了软件参数
                if [ -z "$2" ] || [[ "$2" == -* ]]; then
                    xecho "ERROR" "选项 $1 需要一个参数"
                    exit 1
                fi
                DIY_SOFTWARE="$2"
                shift 2
                ;;
            -o|--output)
                # 检查是否提供了输出目录
                if [ -z "$2" ] || [[ "$2" == -* ]]; then
                    xecho "ERROR" "选项 $1 需要一个参数"
                    exit 1
                fi
                OUTPUT_DIR="$2"
                shift 2
                ;;
            --)  # 结束选项解析
                shift
                break
                ;;
            -*)  # 处理合并短选项（如 -ta）
                options="${1:1}"  # 去掉开头的 '-'
                while [[ -n "$options" ]]; do
                    opt_char="${options:0:1}"  # 取第一个字符
                    options="${options:1}"       # 剩余字符
                    case "$opt_char" in
                        t)
                            TEST_MODE=true
                            ;;
                        a)
                            ALL_SOFTWARE=true
                            ;;
                        s)
                            if [[ -n "$options" ]]; then  # 参数紧跟在选项后（如 -sgit）
                                DIY_SOFTWARE="$options"
                                options=""  # 清空剩余选项
                            elif [[ -n "$2" ]] && [[ "$2" != -* ]]; then  # 参数在下一个位置（如 -s git）
                                DIY_SOFTWARE="$2"
                                shift 1
                            else
                                xecho "ERROR" "选项 -s 需要一个参数"
                                exit 1
                            fi
                            ;;
                        o)
                            if [[ -n "$options" ]]; then
                                OUTPUT_DIR="$options"
                                options=""
                            elif [[ -n "$2" ]] && [[ "$2" != -* ]]; then
                                OUTPUT_DIR="$2"
                                shift 1
                            else
                                xecho "ERROR" "选项 -o 需要一个参数"
                                exit 1
                            fi
                            ;;
                        *)
                            xecho "ERROR" "未知选项: -$opt_char"
                            exit 1
                            ;;
                    esac
                done
                shift  # 已处理完当前合并选项
                ;;
            *)
                xecho "ERROR" "未知参数: $1"
                exit 1
                ;;
        esac
    done
        
    mkdir -p "$OUTPUT_DIR"  # 创建输出目录
    main  # 执行主函数

	# 执行另一个脚本
	# /bin/bash ./zsh2.sh
    # 打印当前系统时间  
    date  
    echo "The End."  
}  

# 执行入口 
# 进入脚本目录位置
cd `dirname $0`
# 获取当前脚本目录位置
# shellfilepath=`pwd`'/'$0
shellfilepath="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# 打印脚本目录地址
echo "[INFO]: 脚本地址 "${shellfilepath}

# 循环检查所有参数
for arg in "$@"; do
    if [[ "$arg" == "-t" || "$arg" == "-test" ]]; then
        TEST_MODE=true
        xecho "Debug" "找到 -t|-test 立即跳出循环"
        # xecho "Debug" "这是一个测试"
        break  # 找到后立即跳出循环
    fi
done

if true  
# if false  
then  
    # echo "[Debug] true"
    # 开始执行  从标准输入中读取并同时写入到标准输出和指定的文件上 
    ## 拼接日志文件地址
    if $TEST_MOD; then 
    # if [[ "$TEST_MODE" == "true" ]]; then 
        #logfilepath=`pwd`'/'$0'.log'
        # logfilepath=`pwd`'/'$0'-'$(date +%Y%m%d)'.log'
        #logfilepath=`pwd`'/'$0'-'$(date +%y%m%d-%H-%M-%S)'.log'
        logfilepath=$shellfilepath'/'$0'-'$(date +%Y%m%d)'.log'
        ## 打印日志文件地址
        # echo "[INFO]: 日志地址" ${logfilepath}
        xecho "DEBUG" "日志地址 ${logfilepath}"
        processControlMain $1 $2 $3 $4 $5 | tee -a ${logfilepath}
    else  
        processControlMain $1 $2 $3 $4 $5
    fi
else  
    echo "[Debug] 函数单元测试 "  
    ## 函数单元测试  
    #  
fi

# 脚本结束